package seatiger.tomcat.coyote.http11;

import seatiger.tomcat.catalina.Constants;
import seatiger.tomcat.coyote.*;
import seatiger.tomcat.coyote.http11.filters.*;
import seatiger.tomcat.util.buf.MessageBytes;

import java.io.IOException;
import java.net.Socket;
import java.util.Date;
import java.util.Map;

/**
 * 处理器线程
 */
public class Http11Processor implements ActionHook {
    private int serverPort = 0;
    private volatile boolean stopped = false;
    private boolean keepAlive = false;
    private Adapter adapter;
    private Request request;

    /**
     * 关联的Response对象
     */
    protected Response response = null;
    //与客户端连接的socket对象
    private Socket socket;
    /**
     * 输出缓冲区，负责缓冲http请求的解析
     */
    private InternalInputBuffer inputBuffer;
    private InternalOutputBuffer outputBuffer;

    public Http11Processor() {
        this.request = new Request();
        this.inputBuffer = new InternalInputBuffer(request, 8 * 1024);
        this.request.setInputBuffer(inputBuffer);
        this.response = new Response();
        this.outputBuffer = new InternalOutputBuffer(response, 8 * 1024);
        this.response.setOutputBuffer(outputBuffer);
        this.response.setHook(this);
        initializeFilters();
    }

    /**
     * 初始化添加过滤器
     */
    private void initializeFilters() {
        //添加读取过滤器
        inputBuffer.addFilter(new IdentityInputFilter());
        inputBuffer.addFilter(new VoidInputFilter());

        //添加输出过滤器
        outputBuffer.addFilter(new IdentityOutputFilter());
        outputBuffer.addFilter(new VoidOutputFilter());
        outputBuffer.addFilter(new ChunkedOutputFilter());
    }

    public void setAdapter(Adapter adapter) {
        this.adapter = adapter;
    }

    /**
     * 解析和客户端连接的socket请求
     */
    public void process(Socket socket) throws IOException {
        this.socket = socket;
        inputBuffer.setInputStream(socket.getInputStream());
        outputBuffer.setOutputStream(socket.getOutputStream());
        keepAlive = true;
        while (keepAlive) {
            //解析请求行
            inputBuffer.parseRequestLine();
            //解析报文头
            inputBuffer.parseHeaders();
            //解析完报文头之后，选择合适的过滤器
            prepareRequest();
            //TODO 解析http,及处理请求
            try {
                adapter.service(request, response);
                //TODO  输出请求行
                inputBuffer.endRequest();
                //看一下有没有下一个请求的报文到达，同时清理一些状态
                inputBuffer.nextRequest();
                outputBuffer.nextRequest();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }

    /**
     * 在读取完报文头之后，选择合适的过滤器
     */
    protected void prepareRequest() {
        InputFilter[] inputFilters = inputBuffer.getFilters();
        int contentLength = request.getContentLength();
        if (contentLength >= 0) {
            inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);
        } else {
            inputBuffer.addActiveFilter(inputFilters[Constants.VOID_FILTER]);
        }
    }

    /**
     * 当提交请求的时候，需要验证一些头部信息，来使用合适的过滤器
     */
    protected void prepareResponse() {
        OutputFilter[] outputFilters = outputBuffer.getFilters();
        int statusCode = response.getStatus();
        if (statusCode == 204 || statusCode == 205 || statusCode == 304) {
            outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
        }
        MessageBytes method = request.method();
        if (method.toString().equals("HEAD")) {
            outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
        }

        int contentLength = response.getContentLength();
        if (contentLength >= 0) {
            outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
            response.addHeader("Content-Length",String.valueOf(contentLength));
        } else {
            //使用chunked
            outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
            response.addHeader("Transfer-Encoding","chunked");
        }
        response.addHeader("Date",new Date().toString());
        response.addHeader("Server","my tomcat");


        outputBuffer.sendStatus();
        Map<String, String> headers = response.getHeaders();
        headers.keySet().forEach(key -> outputBuffer.sendHeader(key,headers.get(key)));
        outputBuffer.endHeaders();

        //TODO 使用chuncked
    }

    @Override
    public void action(ActionCode actionCode, Object param) {
        //提交，第一次写出数据，一般写出报文头
        if (actionCode == ActionCode.ACTION_COMMIT) {
            if (response.isCommited()) {
                return;
            }
            //验证一些头部信息，来决定使用哪个fiter
            prepareResponse();
            try {
                outputBuffer.commit();
            }catch (IOException e){
            }
        }else if (actionCode == ActionCode.ACTION_CLOSE) {
            //数据已经刷出了，做一些收尾的动作
            try {
                outputBuffer.endRequest();
            }catch (Exception e) {

            }
        }
    }
}
